package com.quanshu.exchange.ui.gui.message.chat;

import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.VideoView;

import com.hyphenate.util.EMLog;
import com.hyphenate.util.PathUtil;
import com.quanshu.exchange.R;
import com.quanshu.exchange.support.chat.ChatCommonUtils;
import com.quanshu.exchange.support.utils.AppUtils;
import com.quanshu.exchange.support.utils.ToastHelper;
import com.quanshu.exchange.ui.base.BaseActivity;
import com.quanshu.exchange.ui.widget.CountDownTimeProgressBar;
import com.quanshu.exchange.ui.widget.RoundProgressBar;

import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by jye on 2018/3/13.
 */

public class VideoRecordActivity extends BaseActivity {

    @BindView(R.id.switch_camera)
    ImageView switchCameraBtn;
    @BindView(R.id.video_view)
    VideoView videoView;
    @BindView(R.id.start_record_btn)
    ImageView startRecordBtn;
    @BindView(R.id.stop_record_btn)
    RoundProgressBar stopRecordBtn;
    @BindView(R.id.back_record)
    ImageView backRecordBtn;
    @BindView(R.id.cancel_record)
    ImageView cancelRecordBtn;
    @BindView(R.id.ok_record)
    ImageView okRecordBtn;

    private MediaRecorder mediaRecorder;
    String localPath = "";// path to save recorded video
    private Camera mCamera;
    private int previewWidth = 640;
    private int previewHeight = 480;
    private int frontCamera = 0; // 0 is back camera，1 is front camera
    private SurfaceHolder mSurfaceHolder;
    int defaultVideoFrameRate = 20;

    private PowerManager.WakeLock mWakeLock;
    private final static String CLASS_LABEL = "RecordActivity";
    private MySurfaceCallback mySurfaceCallback;

    private int maxVideoSize = 20000;
    private long timeInterval = 50;

    private CountDownTimeProgressBar countDownTimeProgressBar;
    private MediaScannerConnection msc = null;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);// no title
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);// full screen
        // translucency mode，used in surface view
        getWindow().setFormat(PixelFormat.TRANSLUCENT);
        setContentView(R.layout.activity_record_video);
        ButterKnife.bind(this);
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                CLASS_LABEL);
        mWakeLock.acquire();
        countDownTimeProgressBar = new CountDownTimeProgressBar(stopRecordBtn, maxVideoSize, timeInterval);
        initIntent();
        initView();
        initListener();
    }

    private void initIntent() {

    }

    private void initView() {
        initPreRecordView();
        initVideoView();
        initCamera();
    }

    private void initListener() {
        startRecordBtn.setOnClickListener(view -> clickStartRecord());
        stopRecordBtn.setOnClickListener(view -> clickStopRecord());
        switchCameraBtn.setOnClickListener(view -> clickSwitchCamera());
        backRecordBtn.setOnClickListener(view -> clickBackRecord());
        cancelRecordBtn.setOnClickListener(view -> clickCancelRecord());
        okRecordBtn.setOnClickListener(view -> clickOkRecord());
    }

    private void clickOkRecord() {
        if (TextUtils.isEmpty(localPath)) {
            return;
        }
        if (msc == null)
            msc = new MediaScannerConnection(this,
                    new MediaScannerConnection.MediaScannerConnectionClient() {

                        @Override
                        public void onScanCompleted(String path, Uri uri) {
                            msc.disconnect();
                            setResult(RESULT_OK, getIntent().putExtra("uri", uri));
                            finish();
                        }

                        @Override
                        public void onMediaScannerConnected() {
                            msc.scanFile(localPath, "video/*");
                        }
                    });
        msc.connect();
    }

    private void clickCancelRecord() {
        initPreRecordView();
        stopRecordBtn.setEnabled(true);
        stopRecordBtn.setProgress(0);
        countDownTimeProgressBar.cancel();
    }

    private void clickBackRecord() {
        releaseRecorder();
        releaseCamera();
        finish();
    }

    private void clickSwitchCamera() {
        switchCamera();
    }

    private void clickStopRecord() {
        stopRecordBtn.setEnabled(false);
        stopRecording();
        initStopRecordView();
    }

    private void clickStartRecord() {
        if (!startRecord()) {
            return;
        }
        initStartRecordView();
    }

    private boolean startRecord() {
        if (mediaRecorder == null) {
            if (!initRecorder())
                return false;
        }
        mediaRecorder.setOnErrorListener((mediaRecorder, i, i1) -> stopRecording());
        mediaRecorder.setOnInfoListener((mr, what, extra) -> {
            if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                stopRecording();
                initStopRecordView();
                if (localPath == null) {
                    return;
                }
            }
        });
        mediaRecorder.start();
        return true;
    }

    private void initPreRecordView() {
        startRecordBtn.setVisibility(View.VISIBLE);
        switchCameraBtn.setVisibility(View.VISIBLE);
        stopRecordBtn.setVisibility(View.GONE);
        okRecordBtn.setVisibility(View.GONE);
        cancelRecordBtn.setVisibility(View.GONE);
        backRecordBtn.setVisibility(View.VISIBLE);
    }

    private void initStartRecordView() {
        startRecordBtn.setVisibility(View.GONE);
        stopRecordBtn.setVisibility(View.VISIBLE);
        okRecordBtn.setVisibility(View.GONE);
        cancelRecordBtn.setVisibility(View.GONE);
        backRecordBtn.setVisibility(View.GONE);
        switchCameraBtn.setVisibility(View.GONE);
        stopRecordBtn.setMax(maxVideoSize);
        countDownTimeProgressBar.start();
    }

    private void initStopRecordView() {
        startRecordBtn.setVisibility(View.GONE);
        stopRecordBtn.setVisibility(View.GONE);
        okRecordBtn.setVisibility(View.VISIBLE);
        cancelRecordBtn.setVisibility(View.VISIBLE);
        backRecordBtn.setVisibility(View.GONE);
        switchCameraBtn.setVisibility(View.GONE);
    }

    private void initVideoView() {
        mSurfaceHolder = videoView.getHolder();
        mySurfaceCallback = new MySurfaceCallback();
        mSurfaceHolder.addCallback(mySurfaceCallback);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    private boolean initRecorder() {
        if (!ChatCommonUtils.isSdcardExist()) {
            ToastHelper.toast("未检测到SD卡");
            return false;
        }
        if (mCamera == null) {
            if (!initCamera()) {
                ToastHelper.toast("初始化相机失败，请返回重试");
                return false;
            }
        }
        videoView.setVisibility(View.VISIBLE);
        mCamera.stopPreview();
        mediaRecorder = new MediaRecorder();
        mCamera.unlock();
        mediaRecorder.setCamera(mCamera);
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        if (frontCamera == 1) {
            mediaRecorder.setOrientationHint(270);
        } else {
            mediaRecorder.setOrientationHint(90);
        }
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        // set resolution, should be set after the format and encoder was set
        mediaRecorder.setVideoSize(previewWidth, previewHeight);
        mediaRecorder.setVideoEncodingBitRate(900 * 1024);
        // set frame rate, should be set after the format and encoder was set
        if (defaultVideoFrameRate != -1) {
            mediaRecorder.setVideoFrameRate(defaultVideoFrameRate);
        }
        // set the path for video file
        localPath = PathUtil.getInstance().getVideoPath() + "/"
                + System.currentTimeMillis() + ".mp4";
        mediaRecorder.setOutputFile(localPath);
        mediaRecorder.setMaxDuration(maxVideoSize);
        mediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
        try {
            mediaRecorder.prepare();
        } catch (IllegalStateException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;

    }

    private boolean initCamera() {
        try {
            if (frontCamera == 0) {
                mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
            } else {
                mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
            }
            Camera.Parameters camParams = mCamera.getParameters();
            mCamera.lock();
            mSurfaceHolder = videoView.getHolder();
            mSurfaceHolder.addCallback(mySurfaceCallback);
            mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            mCamera.setDisplayOrientation(90);

        } catch (RuntimeException ex) {
            EMLog.e("video", "init Camera fail " + ex.getMessage());
            return false;
        }
        return true;
    }

    private void handleSurfaceChanged() {
        if (mCamera == null) {
            finish();
            return;
        }
        boolean hasSupportRate = false;
        List<Integer> supportedPreviewFrameRates = mCamera.getParameters()
                .getSupportedPreviewFrameRates();
        if (supportedPreviewFrameRates != null
                && supportedPreviewFrameRates.size() > 0) {
            Collections.sort(supportedPreviewFrameRates);
            for (int i = 0; i < supportedPreviewFrameRates.size(); i++) {
                int supportRate = supportedPreviewFrameRates.get(i);

                if (supportRate == 20) {
                    hasSupportRate = true;
                }

            }
            if (hasSupportRate) {
                defaultVideoFrameRate = 20;
            } else {
                defaultVideoFrameRate = supportedPreviewFrameRates.get(0);
            }

        }

        // get all resolutions which camera provide
        List<Camera.Size> resolutionList = AppUtils.getResolutionList(mCamera);
        if (resolutionList != null && resolutionList.size() > 0) {
            Collections.sort(resolutionList, new ResolutionComparator());
            Camera.Size previewSize = null;
            boolean hasSize = false;

            // use 60*480 if camera support
            for (int i = 0; i < resolutionList.size(); i++) {
                Camera.Size size = resolutionList.get(i);
                if (size != null && size.width == 640 && size.height == 480) {
                    previewSize = size;
                    previewWidth = previewSize.width;
                    previewHeight = previewSize.height;
                    hasSize = true;
                    break;
                }
            }
            // use medium resolution if camera don't support the above resolution
            if (!hasSize) {
                int mediumResolution = resolutionList.size() / 2;
                if (mediumResolution >= resolutionList.size())
                    mediumResolution = resolutionList.size() - 1;
                previewSize = resolutionList.get(mediumResolution);
                previewWidth = previewSize.width;
                previewHeight = previewSize.height;

            }
        }
    }

    public void stopRecording() {
        if (mediaRecorder != null) {
            mediaRecorder.setOnErrorListener(null);
            mediaRecorder.setOnInfoListener(null);
            try {
                mediaRecorder.stop();
            } catch (Exception e) {
                EMLog.e("video", "stopRecording error:" + e.getMessage());
            }
        }
        releaseRecorder();
        if (mCamera != null) {
            mCamera.stopPreview();
            releaseCamera();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mWakeLock == null) {
            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                    CLASS_LABEL);
            mWakeLock.acquire();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mWakeLock != null) {
            mWakeLock.release();
            mWakeLock = null;
        }
        releaseRecorder();
        releaseCamera();
        finish();
    }

    private void releaseRecorder() {
        if (mediaRecorder != null) {
            mediaRecorder.release();
            mediaRecorder = null;
        }
    }

    protected void releaseCamera() {
        try {
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
        } catch (Exception e) {
        }
    }

    public void switchCamera() {
        if (mCamera == null) {
            return;
        }
        if (Camera.getNumberOfCameras() >= 2) {
            switchCameraBtn.setEnabled(false);
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }

            switch (frontCamera) {
                case 0:
                    mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
                    frontCamera = 1;
                    break;
                case 1:
                    mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
                    frontCamera = 0;
                    break;
            }
            try {
                mCamera.lock();
                mCamera.setDisplayOrientation(90);
                mCamera.setPreviewDisplay(videoView.getHolder());
                mCamera.startPreview();
            } catch (IOException e) {
                mCamera.release();
                mCamera = null;
            }
            switchCameraBtn.setEnabled(true);
        }
    }

    public static class ResolutionComparator implements Comparator<Camera.Size> {
        @Override
        public int compare(Camera.Size lhs, Camera.Size rhs) {
            if (lhs.height != rhs.height)
                return lhs.height - rhs.height;
            else
                return lhs.width - rhs.width;
        }

    }

    private class MySurfaceCallback implements SurfaceHolder.Callback {

        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            if (mCamera == null) {
                if (!initCamera()) {
                    ToastHelper.toast("初始化相机失败，请返回重试");
                    return;
                }

            }
            try {
                mCamera.setPreviewDisplay(mSurfaceHolder);
                mCamera.startPreview();
                handleSurfaceChanged();
            } catch (Exception e1) {
                ToastHelper.toast("渲染预览页面失败，请返回重试");
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
            mSurfaceHolder = surfaceHolder;
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

        }
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        releaseRecorder();
        releaseCamera();
        finish();
    }

}
